#pragma once

#include "my_defs.h"
#include "my_atomic.h"
#include "my_spinlock.h"


#define MY_MEM_ITEM_MAGIC                           0xFA5CFFFA
#define MY_ALIGNED_MEM_ITEM_MAGIC                   0xFA5CFFAF
#define MY_MEM_4K_ALIGNMENT                         (1u << 12)
#define MY_MEM_MAX_ALLOC_SIZE                       (1u << 31)


typedef struct {
    uint32_t                magic;
    size_t                  size;
    void                    *next;  /* for free list */
} my_mem_item_head_t;


typedef struct {
    uint32_t            magic;
    size_t              size;
    void                *next;  /* for free list */
    void                *ptr;   /* reserve a ptr space */
} my_aligned_mem_item_head_t;


#define MY_4KALIGNED_MEM_ITEM_OFFSET                            \
    ((MY_MEM_4K_ALIGNMENT - 1) + sizeof(my_aligned_mem_item_head_t))

#define MY_4KALIGNED_MEM_ITEM_PTR(item)                         \
    ((void *)(((size_t)item + (size_t)MY_4KALIGNED_MEM_ITEM_OFFSET) & ~((size_t)MY_MEM_4K_ALIGNMENT - 1)))


typedef struct {
    my_spinlock_t           lock;
    int64_t                 space_size;
    int64_t                 water_level;
    int64_t                 count;
    int64_t                 used;
    void                    *head;
} my_mem_freelist_t;


typedef enum {
    MY_FREELIST_64_MODE         = 0,
    MY_FREELIST_128_MODE        = 1,
    MY_FREELIST_256_MODE        = 2,
    MY_FREELIST_512_MODE        = 3,
    MY_FREELIST_1K_MODE         = 4,
    MY_FREELIST_2K_MODE         = 5,
    MY_FREELIST_4K_MODE         = 6,
    MY_FREELIST_8K_MODE         = 7,
    MY_FREELIST_16K_MODE        = 8,
    MY_FREELIST_32K_MODE        = 9,
    MY_FREELIST_64K_MODE        = 10,
    MY_FREELIST_128K_MODE       = 11,
    MY_FREELIST_256K_MODE       = 12,
    MY_FREELIST_512K_MODE       = 13,
    MY_FREELIST_1M_MODE         = 14,
    MY_FREELIST_2M_MODE         = 15,
    MY_FREELIST_4M_MODE         = 16,
    MY_FREELIST_8M_MODE         = 17,
    MEM_FREELIST_MODE_END       = 18
} my_mem_freelist_mode_t;


typedef struct {
    my_mem_freelist_t       lists[MEM_FREELIST_MODE_END];
    my_bool_t               inited;
} my_mem_freelists_t;


static inline uint32_t
my_mem_freelist_mode_to_size(int mode)
{
    assert(mode >= 0 &&
        mode < MEM_FREELIST_MODE_END);
    return (uint32_t)(1 << (mode + 6));
}


typedef enum {
    MEM_4KALIGNED_FREELIST_4K_MODE          = 0,
    MEM_4KALIGNED_FREELIST_8K_MODE          = 1,
    MEM_4KALIGNED_FREELIST_16K_MODE         = 2,
    MEM_4KALIGNED_FREELIST_32K_MODE         = 3,
    MEM_4KALIGNED_FREELIST_64K_MODE         = 4,
    MEM_4KALIGNED_FREELIST_128K_MODE        = 5,
    MEM_4KALIGNED_FREELIST_256K_MODE        = 6,
    MEM_4KALIGNED_FREELIST_512K_MODE        = 7,
    MEM_4KALIGNED_FREELIST_1M_MODE          = 8,
    MEM_4KALIGNED_FREELIST_2M_MODE          = 9,
    MEM_4KALIGNED_FREELIST_4M_MODE          = 10,
    MEM_4KALIGNED_FREELIST_8M_MODE          = 11,
    MEM_4KALIGNED_FREELIST_MODE_END         = 12           
} my_4kaligned_mem_freelist_mode_t;


typedef struct {
    my_mem_freelist_t       lists[MEM_4KALIGNED_FREELIST_MODE_END];
    my_bool_t               inited;
} my_4kaligned_mem_freelists_t;


static inline uint32_t
my_4kaligned_mem_freelist_mode_to_size(int mode)
{
    assert(mode >= 0 &&
        mode < MEM_4KALIGNED_FREELIST_MODE_END);
    return (uint32_t)(1 << (mode + 12));
}



// interface
void my_mem_init(int64_t water_level);

void *my_mem_alloc(size_t size);

void my_mem_free(void *ptr);

static inline void *
my_mem_calloc(size_t size)
{
    void *ptr = my_mem_alloc(size);
    bzero(ptr, size);
    return ptr;
}

void my_mem_status_report(char *buf, size_t buf_size);

void my_mem_clean();



void my_4kaligned_mem_init(int64_t water_level);

void *my_4kaligned_mem_alloc(size_t size);

void my_4kaligned_mem_free(void *ptr);

void my_4kaligned_mem_status_report(char *buf, size_t buf_size);

void my_4kaligned_mem_clean();

